package club.kingyin.kyblog.core.extend;

import club.kingyin.kyblog.core.IP;
import club.kingyin.kyblog.core.business.dto.CodeEnum;
import club.kingyin.kyblog.core.business.dto.ResultUtil;
import club.kingyin.kyblog.core.utils.cache.CacheUtil;
import club.kingyin.kyblog.core.utils.log.ExecutePostProcessor;
import club.kingyin.kyblog.core.utils.serialization.SerializationUtil;
import com.alibaba.fastjson.JSON;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;

import java.lang.reflect.Field;
import java.time.Duration;

/**
 * @author ：kingyin
 * @date ：创建于 2021/9/11 1:52 上午
 * @description ：
 * @modified By：
 * @version: 1.0.0
 */
public class ExecutePostProcessorLimit implements ExecutePostProcessor<LimitAspect.Handler> {

    @Override
    public Object execute(ProceedingJoinPoint point, LimitAspect.Handler handler) throws Throwable {
        LogLimitConsole limitConsole = CacheUtil.getAnnotation(point, LogLimitConsole.class);
        IP ip = CacheUtil.getAnnotation(point, IP.class);
        if (ip == null) {
            throw new RuntimeException("缺少 @IP 注解");
        }
        String key = ip + "::" + generateParams(point, limitConsole.paramsType(), limitConsole.params());
        String value = handler.getRedisTemplate().opsForValue().get(key);
        ResultUtil res;
        if (StringUtils.isNotEmpty(value)) {
            int count = Integer.parseInt(value);
            if (count >= limitConsole.max()) {
                return ResultUtil.fail("您当前的评论达到上限啦 稍后再试");
            } else {
                res = (ResultUtil) point.proceed();
                Long expire = handler.getRedisTemplate().opsForValue().getOperations().getExpire(key);
                if (res.getCode().equals(CodeEnum.SUCCESS.val()))
                    handler.getRedisTemplate().opsForValue().set(key,String.valueOf(count+1), Duration.ofSeconds(expire));
            }
        } else {
            res = (ResultUtil) point.proceed();
            if (res.getCode().equals(CodeEnum.SUCCESS.val()))
                handler.getRedisTemplate().opsForValue().set(key,String.valueOf(1), Duration.ofSeconds(limitConsole.expire()));
        }
        return res;
    }

    public static String generateParams(ProceedingJoinPoint point, Class<?> type, String[] names) throws NoSuchFieldException, IllegalAccessException {
        Object[] args = point.getArgs();
        StringBuilder paramsSb = new StringBuilder();
        String params;
        for (Object arg : args) {
            if (arg.getClass().getName().equals(type.getName())) {
                for (String name : names) {
                    paramsSb.append(getFieldValueByFieldName(name, arg));
                }
                break;
            }
        }
        params = paramsSb.toString();
//        JSON.parseObject(params);
        if (StringUtils.isNotEmpty(params)) {
            params = DigestUtils.md5Hex(params);
        }
        return params;
    }

    public static Object getFieldValueByFieldName(String fieldName, Object object) throws IllegalAccessException, NoSuchFieldException {
        Field field = object.getClass().getDeclaredField(fieldName);
        //设置对象的访问权限，保证对private的属性的访问
        field.setAccessible(true);
        return field.get(object);
    }

}
